#!/usr/bin/env php
<?php
// 配置允许传入的参数
$allowParam = [
    '-c' => ['default' => 'conf/nginx.conf', 'help' => '指定nginx.conf的路径+文件名'],
    // 这里的PHP_HOME是shell的变量
    '-p' => ['default' => "\$PHP_HOME", 'help' => '指定PHP的家目录所在的位置，不包括 sbin/php-fpm'],
    '-h' => ['help' => '输出帮助'],
    '--nginx' => ['help' => 'nginx的安装目录', 'default' => '/usr/local/nginx'],
    '--pid' => ['help' => 'nginx的pid所在的位置', 'default' => '/usr/local/nginx/logs/nginx.pid']
];
// 解析传入的参数
$params = parseParam($allowParam);
// 如果有需要就输出提示信息
if (isset($params['-h'])) {
    printHelp($allowParam);
    exit(0);
}

// 随便执行一个无意义的sudo命令
// 然后就可以在刚开始的时候就申请sudo权限
// 而不是到后面信息打印到一半的时候才申请
// 增强用户体验
exec("sudo ls");

// 获取PHP的安装目录
$phpDir = $params['-p'] ?? $allowParam['-p']['default'];
// 检查是否启动了PHP-FPM
// 如果没有启动那就启动
echo "检查 PHP-FPM是否启动\n";
$res = ShellUtil::shellExec('pidof php-fpm');
if (0 != $res['code']) { // 没有启动PHP-FPM
    echo "PHP-FPM未启动\n";
    echo "尝试启动PHP-FPM\n";
    $res = ShellUtil::shellExec("sudo {$phpDir}/sbin/php-fpm");
    if (0 != $res['code']) {
        echo "PHP-FPM启动失败\n";
        echo "返回码为：".$res['code'];
        foreach ($res['stderr'] as $line) {
            echo $line;
        }
        exit($res['code']);
    }
}
echo "PHP-FPM 已经启动成功\n\n";


// 如果nginx已经启动 那就重启nginx
// 否则就直接启动nginx
$nginxDir = $params['--nginx'] ?? $allowParam['--nginx']['default'];
$pid = $params['--pid'] ?? $allowParam['--pid']['default'];
$conf = $params['-c'] ?? $allowParam['-c']['default'];

printf("%-25s : %s\n", "使用nginx安装目录", $nginxDir);
printf("%-23s : %s\n", "nginx的pid位置为", $pid);
printf("%-25s : %s\n", "使用配置文件", $conf);

echo "检查 nginx是否启动\n";
if (file_exists($pid) && file_get_contents($pid)) {// nginx 已经开启
    echo "nginx已经启动\n";
    echo "尝试关闭nginx\n";
    $res = ShellUtil::shellExec("sudo {$nginxDir}/sbin/nginx -s stop");

    if (0 != $res['code']) {
        echo "nginx关闭失败\n";
        echo "返回码为：".$res['code'];
        foreach ($res['stderr'] as $line) {
            echo $line;
        }
        exit($res['code']);
    }
    echo "关闭nginx成功\n";
}

echo "尝试启动nginx\n";
$res = ShellUtil::shellExec("sudo {$nginxDir}/sbin/nginx -c {$conf}");
if (0 != $res['code']) {
    echo "nginx打开失败\n";
    echo "返回码为：".$res['code'];
    foreach ($res['stderr'] as $line) {
        echo $line;
    }
    exit($res['code']);
}
echo "启动nginx成功\n";

/**
 * 解析传入的参数
 * @param $allowParam array 允许的参数
 * @return array 解析之后的结果啊
 */
function parseParam(array $allowParam) {
    // 传入来的参数
    global $argv;
    $input = $argv;

    // 解析之后的结果
    $rv = [];
    // index从0开始
    // 因为argv[0]是这个执行文件的名称
    // 1开始的才是参数
    for ($index = 1; $index < count($input); $index ++) {
        $value = $input[$index];
        foreach ($allowParam as $param=>$help) {
            if (0 === strpos($value, $param)) {// 是否包含指定的参数
                if (strlen($param) == strlen($value)) { // 参数和参数值之间有没有空白字符
                    if (isset($input[$index + 1]) && '-' != $input[$index + 1][0]) {
                        // -c dddd
                        // $rv['-c] = 'dddd';
                        $rv[$param] = $input[++ $index];
                    } else {
                        // -c -d
                        // $rv['-c'] = '';
                        // -c 是最后一个参数
                        // $rv['-c'] = '';
                        $rv[$param] = '';
                    }
                } else {
                    // 形如 -cdddddddd
                    // $rv['-c'] = 'dddddddd';
                    $rv[$param] = str_replace($param, '', $input[$index]);
                }
                // 删除已经检查过的param
                // 免得重复检查
                break;
            }
        }
    }
    return $rv;
}

/**
 * 打印提示信息
 * @param array $allowParam
 */
function printHelp(array $allowParam) {
    foreach ($allowParam as $key => $value) {
        printf("%-25s %s\n", $key, $value['help']);
    }
}

class ShellUtil {
    public static function shellExec($command) {
        $proc = proc_open($command, [
            1 => ['pipe','w'], // stdout
            2 => ['pipe','w'], // stderr
        ],$pipes);
        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        return [
            'code' => proc_close($proc),
            'stdout' => explode("\n", $stdout),
            'stderr' => explode("\n", $stderr)
        ];
    }
    // todo 优化
    public static function explainCommand($command) {
        $incr = true;
        $rv = [];
        for ($i = 0, $index = -1; $i < strlen($command); $i ++) {
            if (!CharUtil::isspace($command[$i])) {
                if ($incr) {
                    $index++;
                    $rv[$index] = '';
                    $incr = false;
                }
                $rv[$index] .= $command[$i];
            } else {
                $incr = true;
            }
        }
        return $rv;
    }
}
class CharUtil {
    private static $int = '0123456789';
    private static $eng = 'abcdefghijklmnopqrstuvwxyz';
    private static $space = " \t\n\r\0\x0B";
    public static function isspace(string $char) : bool {
        if (strlen($char) !== 1)
            return false;

        return strpos(self::$space, $char) !== false;
    }
}